/*******************************************************************************
 * Copyright (c) 2010, 2018 西安秦晔信息科技有限公司
 * Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 *******************************************************************************/
package com.qinyeit.webapp.security;

import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SessionKey;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.session.mgt.WebSessionKey;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.util.StringUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.Serializable;

import static com.qinyetech.springstage.core.security.SecurityHttpHeader.X_ACCESS_SESSION_ID;

/**
 * <p>ClassName: com.qinyeit.shirostarterdemo.security.AccessTokenSessionManager
 * <p>Function: 从请求头中读取session id，请求头名称为 X-Access-Token
 * <p>date: 2018-08-11 10:35
 *
 * @author wuqing
 * @version 1.0
 * @since JDK 1.8
 */
@Slf4j
public class AccessTokenSessionManager extends DefaultWebSessionManager {
    //表示sessionID的请求头名称
    public static final String REFERENCED_SESSION_ID_SOURCE="Stateless request";

    public AccessTokenSessionManager() {

        super();
       // super.setSessionIdCookieEnabled(false);//禁用从cookie中读取sessionID
       // super.setSessionIdUrlRewritingEnabled(false); //禁用sessionID 的Url重写
    }

    @Override
    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
        String id = WebUtils.toHttp(request).getHeader(X_ACCESS_SESSION_ID);
        log.debug("session id in header :"+id);
        if(StringUtils.isEmpty(id)){
            //如果没有携带id参数则按照父类的方式在cookie进行获取
            Serializable cookieSessionId=super.getSessionId(request, response);
            log.debug("there is no session id in header, get session id from cookie "+cookieSessionId);
            return cookieSessionId;
        }else{
            //如果请求头中有 authToken 则其值为sessionId
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,REFERENCED_SESSION_ID_SOURCE);
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID,id);
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID,Boolean.TRUE);
            return id;
        }

    }

    /**
     * 解决重复从redis中读取sessionID
     * @param sessionKey
     * @return
     * @throws UnknownSessionException
     */
    protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException {
        Serializable sessionId = getSessionId(sessionKey);
        if (sessionId == null) {
            log.debug("Unable to resolve session ID from SessionKey [{}].  Returning null to indicate a "
                    + "session could not be found.", sessionKey);
            return null;
        }
        // ***************Add By wuqing****************
        ServletRequest request = null;
        if (sessionKey instanceof WebSessionKey) {
            request = ((WebSessionKey) sessionKey).getServletRequest();
        }

        if (request != null) {
            Object s = request.getAttribute(sessionId.toString());
            if (s != null) {
                return (Session) s;
            }
        }
        // ***************Add By wuqing****************
        Session s = retrieveSessionFromDataSource(sessionId);
        if (s == null) {
            // session ID was provided, meaning one is expected to be found, but
            // we couldn't find one:
            String msg = "Could not find session with ID [" + sessionId + "]";
            throw new UnknownSessionException(msg);
        }
        // ***************Add By wuqing****************
        if (request != null) {
            request.setAttribute(sessionId.toString(),s);
        }
        // ***************Add By wuqing****************
        return s;
    }

}
